package com.milhouz.bomberrokon.model;

import java.util.Collection;

import com.milhouz.bomberrokon.sprite.BomberSprite;
import com.milhouz.bomberrokon.sprite.ExplosionTileSprite;
import com.milhouz.bomberrokon.sprite.ItemSprite;
import com.milhouz.bomberrokon.sprite.SolidObject;

public class CollisionDetector {

	private MapModel mapModel;
	private final int COLLISION_ADJUST_VALUE = 2;
	private final int DIR_X[] = { 0, 0, -COLLISION_ADJUST_VALUE, COLLISION_ADJUST_VALUE };
	private final int DIR_Y[] = { -COLLISION_ADJUST_VALUE, COLLISION_ADJUST_VALUE, 0, 0 };

	public CollisionDetector(final MapModel mapModel) {
		this.mapModel = mapModel;
	}

	public ItemSprite detectItemsCollision(final BomberSprite bomberSprite, final Collection<ItemSprite> itemsSprites) {
		ItemSprite removeSprite = null;
		for (ItemSprite curSprite : itemsSprites) {
			if (curSprite != null && isCollidingWith(bomberSprite, curSprite)) {
				curSprite.destroySprite();
				removeSprite = curSprite;
				break;
			}
		}
		if (removeSprite != null) {
			itemsSprites.remove(removeSprite);
		}
		return removeSprite;
	}

	public boolean isExplosionCollision(final SolidObject checkedSolid, ExplosionTileSprite... explosionObjects) {
		// Test whether the collision between this object and any one in the list of objects is happening
		if (explosionObjects != null && explosionObjects.length > 0) {
			for (ExplosionTileSprite solid : explosionObjects) {
				if (solid != null && isCollidingWith(checkedSolid, solid)) {
					return true;
				}
			}
		}
		return false;
	}

	public boolean isCollidingWith(final SolidObject checkedSolid1, final SolidObject checkedSolid2) {
		if (checkedSolid1 != null && checkedSolid2 != null) {
			// Check if the solid object 1 intersects with the solid object 2
			float left1, left2;
			float right1, right2;
			float top1, top2;
			float bottom1, bottom2;

			left1 = checkedSolid1.getSolidX();
			left2 = checkedSolid2.getSolidX();
			right1 = checkedSolid1.getSolidX() + checkedSolid1.getSolidWidth();
			right2 = checkedSolid2.getSolidX() + checkedSolid2.getSolidWidth();
			top1 = checkedSolid1.getSolidY();
			top2 = checkedSolid2.getSolidY();
			bottom1 = (checkedSolid1.getSolidY() + checkedSolid1.getSolidHeight());
			bottom2 = checkedSolid2.getSolidY() + checkedSolid2.getSolidHeight();

			if (bottom1 < top2)
				return false;
			if (top1 > bottom2)
				return false;
			if (right1 < left2)
				return false;
			if (left1 > right2)
				return false;
		}
		return true;
	}

	// ////////////////////////////////////////////////////////////////////
	// New collision detector
	// ////////////////////////////////////////////////////////////////////

	public int checkBomberCollisions(BomberSprite bomberSprite, int direction) {
		// Log.e("BOMBER", "Direction = " + direction);
		Tile[] aroundTiles = mapModel.getAroundTiles(bomberSprite);
		Tile bomberTile = aroundTiles[0];
		Tile checkedTile = null;
		if (direction != BomberSprite.DIRECTION_STOP) {
			for (int i = 1; i < aroundTiles.length; i++) {
				if (aroundTiles[i] == null //
						|| isTileColliding(bomberSprite.getSolidX() + DIR_X[direction - 1] //
						, bomberSprite.getSolidY() + DIR_Y[direction - 1] //
						, bomberSprite.getSolidWidth() //
								, bomberSprite.getSolidHeight() //
								, aroundTiles[i])) {
					bomberSprite.setVelocity(0, 0);
				}
			}
		} else if (direction == BomberSprite.DIRECTION_STOP) {
			if (bomberSprite.mSolidDirection == BomberSprite.DIRECTION_LEFT || bomberSprite.mSolidDirection == BomberSprite.DIRECTION_RIGHT) {
				bomberSprite.setCenterY(bomberTile.getCenterTileY());
			} else if (bomberSprite.mSolidDirection == BomberSprite.DIRECTION_UP || bomberSprite.mSolidDirection == BomberSprite.DIRECTION_DOWN) {
				bomberSprite.setCenterX(bomberTile.getCenterTileX());
			}
		}

		if (direction == BomberSprite.DIRECTION_LEFT) {
			checkedTile = aroundTiles[BomberSprite.DIRECTION_LEFT];
			if (checkedTile == null) {
				bomberSprite.setCenterX(aroundTiles[BomberSprite.DIRECTION_RIGHT].getCenterTileX());
				return BomberSprite.DIRECTION_STOP;
			} else if (checkedTile.getObjectTile() != MapModel.TILE_EMPTY //
					&& isTileCollideLeft(bomberSprite, checkedTile)) {
				bomberSprite.setCenterX(bomberTile.getCenterTileX());
				// Check if redirection UP or DOWN
				if (bomberSprite.getCenterY() > checkedTile.getCenterTileY() //
						// && tile upper left is empty
						&& aroundTiles[BomberSprite.DIRECTION_UP] != null //
						&& !isTileCollideUp(bomberSprite, aroundTiles[BomberSprite.DIRECTION_UP]) // 
						&& isTileCollideDown(bomberSprite, checkedTile)) {
					// Go down
					return BomberSprite.DIRECTION_DOWN;
				} else if (bomberSprite.getCenterY() < checkedTile.getCenterTileY() //
						// && tile bottom left is empty
						&& aroundTiles[BomberSprite.DIRECTION_DOWN] != null //
						&& !isTileCollideDown(bomberSprite, aroundTiles[BomberSprite.DIRECTION_DOWN]) //
						&& isTileCollideUp(bomberSprite, checkedTile)) {
					// Go up
					return BomberSprite.DIRECTION_UP;
				}
				return BomberSprite.DIRECTION_STOP;
			}
			bomberSprite.setCenterY(bomberTile.getCenterTileY());
		} else if (direction == BomberSprite.DIRECTION_RIGHT) {
			checkedTile = aroundTiles[BomberSprite.DIRECTION_RIGHT];
			if (checkedTile == null) {
				bomberSprite.setCenterX(aroundTiles[BomberSprite.DIRECTION_LEFT].getCenterTileX());
				return BomberSprite.DIRECTION_STOP;
			} else if (checkedTile.getObjectTile() != MapModel.TILE_EMPTY //
					&& isTileCollideRight(bomberSprite, checkedTile)) {
				bomberSprite.setCenterX(bomberTile.getCenterTileX());
				// Check if redirection UP or DOWN
				if (bomberSprite.getCenterY() > checkedTile.getCenterTileY() //
						// && tile upper left is empty
						&& aroundTiles[BomberSprite.DIRECTION_UP] != null //
						&& !isTileCollideUp(bomberSprite, aroundTiles[BomberSprite.DIRECTION_UP]) // 
						&& isTileCollideDown(bomberSprite, checkedTile)) {
					// Go down
					bomberSprite.setCenterY(bomberTile.getCenterTileY());
					return BomberSprite.DIRECTION_DOWN;
				} else if (bomberSprite.getCenterY() < checkedTile.getCenterTileY() //
						// && tile bottom left is empty
						&& aroundTiles[BomberSprite.DIRECTION_DOWN] != null //
						&& !isTileCollideDown(bomberSprite, aroundTiles[BomberSprite.DIRECTION_DOWN]) //
						&& isTileCollideUp(bomberSprite, checkedTile)) {
					// Go up
					bomberSprite.setCenterY(bomberTile.getCenterTileY());
					return BomberSprite.DIRECTION_UP;
				}
				return BomberSprite.DIRECTION_STOP;
			}
			bomberSprite.setCenterY(bomberTile.getCenterTileY());
		} else if (direction == BomberSprite.DIRECTION_UP) {
			checkedTile = aroundTiles[BomberSprite.DIRECTION_UP];
			if (checkedTile == null) {
				bomberSprite.setCenterY(aroundTiles[BomberSprite.DIRECTION_DOWN].getCenterTileY());
				return BomberSprite.DIRECTION_STOP;
			} else if (checkedTile.getObjectTile() != MapModel.TILE_EMPTY //
					&& isTileCollideUp(bomberSprite, checkedTile)) {
				bomberSprite.setCenterY(bomberTile.getCenterTileY());
				// Check if redirection LEFT or RIGHT
				if (bomberSprite.getCenterX() > checkedTile.getCenterTileX() //
						// && tile upper left is empty
						&& aroundTiles[BomberSprite.DIRECTION_RIGHT] != null //
						&& !isTileCollideUp(bomberSprite, aroundTiles[BomberSprite.DIRECTION_RIGHT]) // 
						&& isTileCollideDown(bomberSprite, checkedTile)) {
					// Go right
					bomberSprite.setCenterX(bomberTile.getCenterTileX());
					return BomberSprite.DIRECTION_RIGHT;
				} else if (bomberSprite.getCenterX() < checkedTile.getCenterTileX() //
						// && tile bottom left is empty
						&& aroundTiles[BomberSprite.DIRECTION_LEFT] != null //
						&& !isTileCollideDown(bomberSprite, aroundTiles[BomberSprite.DIRECTION_LEFT]) //
						&& isTileCollideUp(bomberSprite, checkedTile)) {
					// Go left
					bomberSprite.setCenterX(bomberTile.getCenterTileX());
					return BomberSprite.DIRECTION_LEFT;
				}
				return BomberSprite.DIRECTION_STOP;
			}
			bomberSprite.setCenterX(bomberTile.getCenterTileX());
		} else if (direction == BomberSprite.DIRECTION_DOWN) {
			checkedTile = aroundTiles[BomberSprite.DIRECTION_DOWN];
			if (checkedTile == null) {
				bomberSprite.setCenterY(aroundTiles[BomberSprite.DIRECTION_UP].getCenterTileY());
				return BomberSprite.DIRECTION_STOP;
			} else if (checkedTile.getObjectTile() != MapModel.TILE_EMPTY //
					&& isTileCollideDown(bomberSprite, checkedTile)) {
				bomberSprite.setCenterY(bomberTile.getCenterTileY());
				// Check if redirection LEFT or RIGHT
				if (bomberSprite.getCenterX() > checkedTile.getCenterTileX() //
						// && tile upper left is empty
						&& aroundTiles[BomberSprite.DIRECTION_RIGHT] != null //
						&& !isTileCollideUp(bomberSprite, aroundTiles[BomberSprite.DIRECTION_RIGHT]) // 
						&& isTileCollideDown(bomberSprite, checkedTile)) {
					// Go right
					bomberSprite.setCenterX(bomberTile.getCenterTileX());
					return BomberSprite.DIRECTION_RIGHT;
				} else if (bomberSprite.getCenterX() < checkedTile.getCenterTileX() //
						// && tile bottom left is empty
						&& aroundTiles[BomberSprite.DIRECTION_LEFT] != null //
						&& !isTileCollideDown(bomberSprite, aroundTiles[BomberSprite.DIRECTION_LEFT]) //
						&& isTileCollideUp(bomberSprite, checkedTile)) {
					// Go left
					bomberSprite.setCenterX(bomberTile.getCenterTileX());
					return BomberSprite.DIRECTION_LEFT;
				}
				return BomberSprite.DIRECTION_STOP;
			}
			bomberSprite.setCenterX(bomberTile.getCenterTileX());
		}
		return direction;
	}

	private boolean isTileCollideLeft(BomberSprite bomberSprite, Tile checkedTile) {
		int leftBomber = (int) bomberSprite.getSolidX() + DIR_X[BomberSprite.DIRECTION_LEFT - 1];
		int rightTile = checkedTile.getTileX() + checkedTile.getTileSize();
		if (leftBomber <= rightTile) {
			return true;
		}
		return false;
	}

	private boolean isTileCollideRight(BomberSprite bomberSprite, Tile checkedTile) {
		int rightBomber = (int) (bomberSprite.getCenterX() + (checkedTile.getTileSize() / 2)) + DIR_X[BomberSprite.DIRECTION_RIGHT - 1];
		int leftTile = checkedTile.getTileX();
		if (rightBomber >= leftTile) {
			return true;
		}
		return false;
	}

	private boolean isTileCollideDown(BomberSprite bomberSprite, Tile checkedTile) {
		int bottomBomber = (int) (bomberSprite.getCenterY() + (checkedTile.getTileSize() / 2)) + DIR_Y[BomberSprite.DIRECTION_DOWN - 1];
		int topTile = checkedTile.getTileY();
		if (bottomBomber >= topTile) {
			return true;
		}
		return false;
	}

	private boolean isTileCollideUp(BomberSprite bomberSprite, Tile checkedTile) {
		int topBomber = (int) (bomberSprite.getCenterY() - (checkedTile.getTileSize() / 2)) + DIR_Y[BomberSprite.DIRECTION_UP - 1];
		int bottomTile = checkedTile.getTileY() + checkedTile.getTileSize();
		if (topBomber <= bottomTile) {
			return true;
		}
		return false;
	}

	private boolean isTileColliding(float x, float y, float w, float h, final Tile tile) {
		if (tile != null) {
			// Check if the solid object 1 intersects with the solid object 2
			float left1, left2;
			float right1, right2;
			float top1, top2;
			float bottom1, bottom2;

			left1 = x;
			left2 = tile.getTileX();
			right1 = x + w;
			right2 = tile.getTileX() + tile.getTileSize();
			top1 = y;
			top2 = tile.getTileY();
			bottom1 = y + h;
			bottom2 = tile.getTileY() + tile.getTileSize();

			if (bottom1 < top2)
				return false;
			if (top1 > bottom2)
				return false;
			if (right1 < left2)
				return false;
			if (left1 > right2)
				return false;
		}
		return true;
	}
}
